package com.jcli.jb51_net.article._198500_基于TCP协议网络socket编程;

import javax.swing.*;
import java.awt.*;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketException;
import java.util.ArrayList;
import java.util.List;

public class MultiThreadedTCPServerGUI extends JFrame {
    private JTextArea logTextArea;
    private JButton startButton;
    private JButton stopButton;
    private JTextField ipField;
    private JTextField portField;
    private JTextField messageField;
    private JButton sendButton;

    private ServerSocket serverSocket;
    private List<ClientHandler> clientHandlers = new ArrayList<>();

    private static final int DEFAULT_PORT = 8008;

    public MultiThreadedTCPServerGUI() {
        setTitle("多线程TCP服务端");
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setSize(600, 400);
        setLocationRelativeTo(null);

        JPanel topPanel = new JPanel(new FlowLayout());
        JPanel centerPanel = new JPanel(new BorderLayout());
        JPanel bottomPanel = new JPanel(new FlowLayout());

        startButton = new JButton("启动服务");
        stopButton = new JButton("停止服务");
        stopButton.setEnabled(false);

        ipField = new JTextField("127.0.0.1", 20);
        portField = new JTextField(String.valueOf(DEFAULT_PORT), 5);
        messageField = new JTextField(20);
        sendButton = new JButton("发送");

        topPanel.add(new JLabel("IP:"));
        topPanel.add(ipField);
        topPanel.add(new JLabel("端口:"));
        topPanel.add(portField);
        topPanel.add(startButton);
        topPanel.add(stopButton);

        logTextArea = new JTextArea();
        logTextArea.setEditable(false);

        JScrollPane scrollPane = new JScrollPane(logTextArea);
        centerPanel.add(scrollPane, BorderLayout.CENTER);

        bottomPanel.add(new JLabel("发送消息:"));
        bottomPanel.add(messageField);
        bottomPanel.add(sendButton);

        add(topPanel, BorderLayout.NORTH);
        add(centerPanel, BorderLayout.CENTER);
        add(bottomPanel, BorderLayout.SOUTH);

        startButton.addActionListener(e -> startServer());
        stopButton.addActionListener(e -> stopServer());
        sendButton.addActionListener(e -> sendMessage());

        setVisible(true);
    }

    private void startServer() {
        try {
            String ip = ipField.getText();
            int port = Integer.parseInt(portField.getText());
            serverSocket = new ServerSocket(port, 50, InetAddress.getByName(ip));

            logTextArea.append("服务器启动监听在" + ip + ":" + port + "端口...\n");

            startButton.setEnabled(false);
            stopButton.setEnabled(true);
            new Thread(() -> {
                //服务器关闭时应该中断等待连接的accept()，以防止这种情况的发生。
                while (!serverSocket.isClosed()) {
                    Socket clientSocket = null;
                    try {
                        clientSocket = serverSocket.accept();
                        ClientHandler clientHandler = new ClientHandler(clientSocket);
                        clientHandlers.add(clientHandler);
                        new Thread(clientHandler).start();
                    } catch (SocketException se) {
                        // 如果服务器Socket关闭，则跳出循环
                        break;
                    }catch (IOException e) {
                        e.printStackTrace();
                    }

                }
            }).start();

        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private void stopServer() {
        try {
            for (ClientHandler clientHandler : clientHandlers) {
                clientHandler.close();
            }
            clientHandlers.clear();
            if (serverSocket != null && !serverSocket.isClosed()) {
                serverSocket.close();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }

        startButton.setEnabled(true);
        stopButton.setEnabled(false);
        logTextArea.append("服务器已停止\n");
    }

    private void sendMessage() {
        String message = messageField.getText();
        for (ClientHandler clientHandler : clientHandlers) {
            clientHandler.sendMessage("服务器消息：" + message);
        }
        logTextArea.append("服务器发送消息：" + message + "\n");
        messageField.setText("");
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(MultiThreadedTCPServerGUI::new);
    }

    private class ClientHandler implements Runnable {
        private Socket clientSocket;
        private BufferedReader reader;
        private PrintWriter writer;

        public ClientHandler(Socket clientSocket) {
            this.clientSocket = clientSocket;
            try {
                reader = new BufferedReader(new InputStreamReader(clientSocket.getInputStream(), "utf-8"));
                writer = new PrintWriter(clientSocket.getOutputStream(), true);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        @Override
        public void run() {
            try {
                String msg;
                while ((msg = reader.readLine()) != null) {
                    logTextArea.append("客户端消息：" + msg + "\n");
                    sendMessage("服务器消息：" + msg);
                }
            } catch (IOException e) {
                // 客户端断开连接时会抛出 IOException
                logTextArea.append("客户端断开连接\n");
            } finally {
                close();
            }
        }

        public void sendMessage(String message) {
            writer.println(message);
        }

        public void close() {
            try {
                if (clientSocket != null && !clientSocket.isClosed()) {
                    clientSocket.close();
                }
                if (reader != null) {
                    reader.close();
                }
                if (writer != null) {
                    writer.close();
                }
                clientHandlers.remove(this);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}
